<template>
  <view class="he-up-load-image flex flex-wrap">
    <view class="he-list-item" v-for="(item, index) in lists" :key="index">
      <view @tap.stop="deleteItem(index)" class="he-delete-icon iconfont iconevaluate_uploadpictures_deleto"></view>
      <image
        @tap.stop="doPreviewImage(item.url || item.path, index)"
        class="he-preview-image"
        :mode="imageMode"
        :src="item.url || item.path"
      ></image>
    </view>
    <button
      @tap="selectFile"
      v-if="maxCount > lists.length"
      class="cu-btn he-list-item lex flex-direction ustify-center align-center"
    >
      <view class="iconfont iconevaluate_uploadpictures"></view>
      <view class="he-add-text">{{ addText }}</view>
    </button>
    <he-toast v-model="loading">
      <view class="he-loading flex flex-direction align-center">
        <image :src="ipAddress + '/upload-loading.gif'" class="he-loading__image"></image>
        <text>图片上传中...</text>
      </view>
    </he-toast>
  </view>
</template>

<script>
import heToast from '@/components/he-toast.vue';

export default {
  name: 'he-upload-image',
  components: {
    heToast
  },
  props: {
    // 是否开启图片多选，部分安卓机型不支持
    multiple: {
      type: Boolean,
      default: true
    },
    // 预览上传的图片时的裁剪模式，和image组件mode属性一致
    imageMode: {
      type: String,
      default: 'aspectFill'
    },
    // 最大上传数量
    maxCount: {
      type: [String, Number],
      default: 9
    },
    // album 从相册选图，camera 使用相机，默认二者都有。如需直接开相机或直接选相册，请只使用一个选项
    sourceType: {
      type: Array,
      default() {
        return ['album', 'camera'];
      }
    },
    // 是否自动上传
    autoUpload: {
      type: Boolean,
      default: true
    },
    // 允许上传的图片后缀
    limitType: {
      type: Array,
      default() {
        // 支付宝小程序真机选择图片的后缀为"image"
        return ['png', 'jpg', 'jpeg', 'webp', 'gif', 'image'];
      }
    },
    // 上传前的钩子，每个文件上传前都会执行
    beforeUpload: {
      type: Function,
      default: null
    },
    // 是否在点击预览图后展示全屏图片预览
    previewFullImage: {
      type: Boolean,
      default: true
    },
    // 所选的图片的尺寸, 可选值为original compressed
    sizeType: {
      type: Array,
      default() {
        return ['original'];
      }
    },
    // 上传的文件字段名
    name: {
      type: String,
      default: 'file'
    },
    // 额外携带的参数
    formData: {
      type: Object,
      default() {
        return {};
      }
    },
    // 头部信息
    header: {
      type: Object,
      default() {
        return {};
      }
    },
    // 在各个回调事件中的最后一个参数返回，用于区别是哪一个组件的事件
    index: {
      type: [Number, String],
      default: ''
    },
    // 文件大小限制，单位为byte
    maxSize: {
      type: [String, Number],
      default: function () {
        return 2097152;
      }
    },
    addText: {
      type: [String],
      default: '添加图片'
    }
  },
  data() {
    return {
      lists: [],
      uploading: false,
      loading: false
    };
  },
  methods: {
    selectFile: function () {
      const {
        name = '',
        maxCount,
        multiple,
        maxSize,
        sizeType,
        lists,
        camera,
        compressed,
        maxDuration,
        sourceType
      } = this;
      let chooseFile = null;
      const newMaxCount = maxCount - lists.length;
      chooseFile = new Promise((resolve, reject) => {
        uni.chooseImage({
          count: multiple ? (newMaxCount > 9 ? 9 : newMaxCount) : 1,
          sourceType: sourceType,
          sizeType: ['original'],
          success: resolve,
          fail: reject
        });
      });
      chooseFile
        .then(res => {
          let file = null;
          let listOldLength = this.lists.length;
          res.tempFiles.map((val, index) => {
            // 检查文件后缀是否允许，如果不在this.limitType内，就会返回false
            if (!this.checkFileExt(val)) return;
            // 如果是非多选，index大于等于1或者超出最大限制数量时，不处理
            if (!multiple && index >= 1) return;
            if (val.size > maxSize && maxSize > 0) {
              this.$h.toast('超出允许的文件大小');
            } else {
              if (maxCount <= lists.length) {
                this.$h.toast('超出最大允许的文件个数');
                return;
              }
              lists.push({
                url: val.path,
                progress: 0,
                error: false,
                file: val
              });
            }
          });
          // 每次图片选择完，抛出一个事件，并将当前内部选择的图片数组抛出去
          this.$emit('on-choose-complete', this.lists, this.index);

          if (this.autoUpload) {
            this.loading = true;
            this.uploadFile(listOldLength);
          }
        })
        .catch(err => {});
    },
    async uploadFile(index = 0) {
      let _this = this;
      if (this.uploading) return;
      // 全部上传完成
      if (index >= this.lists.length) {
        this.loading = false;
        this.$emit('on-uploaded', this.lists, this.index);
        return;
      }
      this.lists[index].error = false;
      this.uploading = true;
      this.$h.srcToBase64(this.lists[index].url).then(function (res) {
        _this.$heshop
          .upload(res)
          .then(function (data) {
            _this.uploading = false;
            _this.lists[index].response = data;
            _this.$emit('on-success', data, index, _this.lists, _this.index);
            _this.uploadFile(index + 1);
          })
          .catch(function (err) {
            _this.uploading = false;
            _this.loading = false;
            _this.uploadError(index, err);
          });
      });
    },
    // 上传失败
    uploadError(index, err) {
      this.lists[index].progress = 0;
      this.lists[index].error = true;
      this.lists[index].response = null;

      this.$h.toast(err.data.message);
      this.$emit('on-error', err, index, this.lists, this.index);
    },
    // 判断文件后缀是否允许
    checkFileExt(file) {
      // 检查是否在允许的后缀中
      let noArrowExt = false;
      // 获取后缀名
      let fileExt = '';
      const reg = /.+\./;
      // 如果是H5，需要从name中判断
      // #ifdef H5
      fileExt = file.name.replace(reg, '').toLowerCase();
      // #endif
      // 非H5，需要从path中读取后缀
      // #ifndef H5
      fileExt = file.path.replace(reg, '').toLowerCase();
      // #endif
      // 使用数组的some方法，只要符合limitType中的一个，就返回true
      noArrowExt = this.limitType.some(ext => {
        // 转为小写
        return ext.toLowerCase() === fileExt;
      });
      if (!noArrowExt) this.$h.toast(`不允许选择${fileExt}格式的文件`);
      return noArrowExt;
    },
    deleteItem: function (index) {
      this.lists.splice(index, 1);
      this.$emit('on-remove', index, this.lists, this.index);
      this.$h.toast('移除成功');
    },
    // 预览图片
    doPreviewImage: function (url) {
      if (!this.previewFullImage) return;
      const images = this.lists.map(item => item.url || item.path);
      this.$utils.doPreviewImage(url, images);
    }
  },
  mounted() {}
};
</script>

<style scoped lang="scss">
.he-list-item {
  width: 150px;
  height: 150px;
  margin: 0 20px 20px 0;
  background: rgb(244, 245, 246);
  position: relative;
  border-radius: 8px;
}

.he-add-text {
  font-size: 22px;
  font-family: PingFang SC;
  font-weight: 500;
  color: #666666;
  margin-top: 5px;
}

.iconevaluate_uploadpictures {
  color: RGBA(102, 102, 102, 1);
  width: 48px;
  height: 48px;
  font-size: 48px;
  margin-bottom: 5px;
}

.he-delete-icon {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 10;
  width: 60px;
  height: 60px;
  padding: 16px;
  transform: translate(50%, -50%);
  font-size: 28px;
  color: rgba(245, 33, 45, 1);
}

.he-preview-image {
  width: 100%;
  height: 100%;
  border-radius: 8px;
  display: block;
}

.he-loading {
  width: 100%;
  height: 100%;
  font-size: 28px;
  font-family: PingFang SC;
  font-weight: 500;
  color: #ffffff;
  text-align: center;
}

.he-loading__image {
  width: 96px;
  height: 96px;
  margin-top: 52px;
  margin-bottom: 40px;
}
</style>
